package jp.co.toshiba.ffsa.common;

import static jp.co.toshiba.ffsa.service.common.ConstantValue.iv;
import static jp.co.toshiba.ffsa.service.common.ConstantValue.key;
import static org.seasar.struts.util.MessageResourcesUtil.*;

import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.digest.DigestUtils;
import org.seasar.framework.util.Base64Util;

public class Crypto {
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static Cipher aesCipher = null;

    /**
     * 渡された文字列をAES256で暗号化します
     * @param plainText
     * @return AES256で暗号化された文字列
     * @throws Exception
     */
    public static String encrypt(String plainText) throws Exception {
        return encryptStringByAES256(plainText, key, iv);
    }

    /**
     * 渡された文字列をAES256で復号します
     * @param encryptedText
     * @return AES256で復号された文字列
     * @throws Exception
     */
    public static String decrypt(String encryptedText) throws Exception {
        return decryptStrToStrByAES256(encryptedText, key, iv);
    }

    /**
     * 文字列をAES256で暗号化します。<br><br>
     * 暗号化モード：CBC<br>
     * パディング：PKCS5<br>
     * @param plainText (必須)暗号化する文字列<br>
     * @param key (必須)暗号化鍵<br>
     * @param iv (必須)初期化ベクタ<br>
     * @return (必須)暗号化された文字列<br>
     * @throws Exception<br>
     */
    private static String encryptStringByAES256(String plainText,
            String key,
            String iv) throws Exception {
        initCipher(key, iv, Cipher.ENCRYPT_MODE);
        return Base64Util.encode(aesCipher.doFinal(plainText.getBytes(getMessage("charset"))));
    }

    /**
     * AES256で暗号化されている文字列を復号し、文字列で返します。<br><br>
     * 暗号化モード：CBC<br>
     * パディング：PKCS5<br>
     * @param encryptedText (必須)復号する文字列<br>
     * @param key (必須)復号鍵<br>
     * @param iv (必須)初期化ベクタ<br>
     * @return (必須)復号された文字列<br>
     * @throws Exception<br>
     */
    private static String decryptStrToStrByAES256(String encryptedText,
            String key,
            String iv) throws Exception {
        initCipher(key, iv, Cipher.DECRYPT_MODE);
        return new String(aesCipher.doFinal(Base64Util.decode(encryptedText)), getMessage("charset"));
    }

    /*
     * 暗号化クラス初期化
     */
    private static void initCipher(String key,
            String iv,
            int mode) throws Exception {
        byte[] secretyKeyBytes = DigestUtils.sha256(key);
        byte[] ivBytes = DigestUtils.md5(iv);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretyKeyBytes, ALGORITHM);
        aesCipher = Cipher.getInstance(TRANSFORMATION);
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        aesCipher.init(mode, secretKeySpec, ivSpec);
    }

}
